package com.kexio.user.dto;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.kexio.common.page.PageQuery;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;

/**
 * 菜单统一DTO
 * 
 * 用于菜单管理的统一数据传输，支持创建、更新、响应、分页查询等场景。
 * 继承PageQuery支持分页，采用统一DTO设计减少类型转换复杂度。
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
public class MenuDTO extends PageQuery implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    // ==================== 基础字段 ====================
    
    /**
     * 菜单ID（响应时使用，创建时忽略）- UUID字符串
     */
    private String id;
    
    /**
     * 租户ID
     */
    private String tenantId;
    
    /**
     * 父菜单ID - UUID字符串
     */
    private String parentId;
    
    /**
     * 菜单名称（英文标识）
     */
    @NotBlank(message = "菜单名称不能为空")
    @Size(min = 2, max = 50, message = "菜单名称长度必须在2-50个字符之间")
    @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_-]*$", message = "菜单名称格式不正确，必须以字母开头，只能包含字母、数字、下划线和短横线")
    private String name;
    
    /**
     * 菜单标题（显示用）
     */
    @NotBlank(message = "菜单标题不能为空")
    @Size(min = 1, max = 50, message = "菜单标题长度必须在1-50个字符之间")
    private String title;
    
    // ==================== 路由字段 ====================
    
    /**
     * 路由路径
     */
    @Size(max = 200, message = "路由路径长度不能超过200个字符")
    private String path;
    
    /**
     * 前端组件路径
     */
    @Size(max = 200, message = "组件路径长度不能超过200个字符")
    private String component;
    
    /**
     * 菜单图标
     */
    @Size(max = 50, message = "菜单图标长度不能超过50个字符")
    private String icon;
    
    // ==================== 类型和权限字段 ====================
    
    /**
     * 菜单类型：M-目录，C-菜单，F-按钮
     */
    @NotBlank(message = "菜单类型不能为空")
    private String menuType;
    
    /**
     * 权限标识（可选，在新架构下权限通过menu_id字段直接关联菜单）
     */
    @Size(max = 100, message = "权限标识长度不能超过100个字符")
    private String permission;
    
    // ==================== 显示控制字段 ====================
    
    /**
     * 排序号
     */
    private Integer orderNo;
    
    /**
     * 是否外链：true-是，false-否
     */
    private Boolean isFrame;
    
    /**
     * 是否缓存：true-缓存，false-不缓存
     */
    private Boolean isCache;
    
    /**
     * 是否可见：true-显示，false-隐藏
     */
    @NotNull(message = "是否可见不能为空")
    private Boolean visible;
    
    /**
     * 状态：1-启用，0-禁用
     */
    @NotNull(message = "状态不能为空")
    @Min(value = 0, message = "状态值最小为0")
    @Max(value = 1, message = "状态值最大为1")
    private Integer status;
    
    // ==================== 扩展字段 ====================
    
    /**
     * 菜单元数据（JSON格式，存储额外配置）
     */
    private String metadata;
    
    /**
     * 菜单元数据映射（解析后的metadata，响应时使用）
     */
    private Map<String, Object> metadataMap;
    
    // ==================== 审计字段 ====================
    
    /**
     * 创建人
     */
    private String createBy;
    
    /**
     * 创建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    
    /**
     * 更新人
     */
    private String updateBy;
    
    /**
     * 更新时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    
    // ==================== 关联字段（响应时使用） ====================
    
    /**
     * 父菜单信息（响应时可能包含）
     */
    private MenuDTO parentMenu;
    
    /**
     * 子菜单列表（响应时可能包含）
     */
    private List<MenuDTO> children;
    
    /**
     * 关联的权限列表（响应时可能包含）
     */
    private List<PermissionDTO> permissions;
    
    /**
     * 菜单路径（从根菜单到当前菜单的路径）
     */
    private String menuPath;
    
    /**
     * 菜单层级深度
     */
    private Integer menuLevel;
    
    // ==================== 构造函数 ====================
    
    public MenuDTO() {
    }
    
    // ==================== Getter/Setter ====================
    
    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    public String getTenantId() {
        return tenantId;
    }
    
    public void setTenantId(String tenantId) {
        this.tenantId = tenantId;
    }
    
    public String getParentId() {
        return parentId;
    }
    
    public void setParentId(String parentId) {
        this.parentId = parentId;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getTitle() {
        return title;
    }
    
    public void setTitle(String title) {
        this.title = title;
    }
    
    public String getPath() {
        return path;
    }
    
    public void setPath(String path) {
        this.path = path;
    }
    
    public String getComponent() {
        return component;
    }
    
    public void setComponent(String component) {
        this.component = component;
    }
    
    public String getIcon() {
        return icon;
    }
    
    public void setIcon(String icon) {
        this.icon = icon;
    }
    
    public String getMenuType() {
        return menuType;
    }
    
    public void setMenuType(String menuType) {
        this.menuType = menuType;
    }
    
    public String getPermission() {
        return permission;
    }
    
    public void setPermission(String permission) {
        this.permission = permission;
    }
    
    public Integer getOrderNo() {
        return orderNo;
    }
    
    public void setOrderNo(Integer orderNo) {
        this.orderNo = orderNo;
    }
    
    public Boolean getIsFrame() {
        return isFrame;
    }
    
    public void setIsFrame(Boolean isFrame) {
        this.isFrame = isFrame;
    }
    
    public Boolean getIsCache() {
        return isCache;
    }
    
    public void setIsCache(Boolean isCache) {
        this.isCache = isCache;
    }
    
    public Boolean getVisible() {
        return visible;
    }
    
    public void setVisible(Boolean visible) {
        this.visible = visible;
    }
    
    public Integer getStatus() {
        return status;
    }
    
    public void setStatus(Integer status) {
        this.status = status;
    }
    
    public String getMetadata() {
        return metadata;
    }
    
    public void setMetadata(String metadata) {
        this.metadata = metadata;
    }
    
    public Map<String, Object> getMetadataMap() {
        return metadataMap;
    }
    
    public void setMetadataMap(Map<String, Object> metadataMap) {
        this.metadataMap = metadataMap;
    }
    
    public String getCreateBy() {
        return createBy;
    }
    
    public void setCreateBy(String createBy) {
        this.createBy = createBy;
    }
    
    public LocalDateTime getCreateTime() {
        return createTime;
    }
    
    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }
    
    public String getUpdateBy() {
        return updateBy;
    }
    
    public void setUpdateBy(String updateBy) {
        this.updateBy = updateBy;
    }
    
    public LocalDateTime getUpdateTime() {
        return updateTime;
    }
    
    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }
    
    public MenuDTO getParentMenu() {
        return parentMenu;
    }
    
    public void setParentMenu(MenuDTO parentMenu) {
        this.parentMenu = parentMenu;
    }
    
    public List<MenuDTO> getChildren() {
        return children;
    }
    
    public void setChildren(List<MenuDTO> children) {
        this.children = children;
    }
    
    public List<PermissionDTO> getPermissions() {
        return permissions;
    }
    
    public void setPermissions(List<PermissionDTO> permissions) {
        this.permissions = permissions;
    }
    
    public String getMenuPath() {
        return menuPath;
    }
    
    public void setMenuPath(String menuPath) {
        this.menuPath = menuPath;
    }
    
    public Integer getMenuLevel() {
        return menuLevel;
    }
    
    public void setMenuLevel(Integer menuLevel) {
        this.menuLevel = menuLevel;
    }
    
    // ==================== 转换方法 ====================
    
    /**
     * 从Menu实体转换为MenuDTO
     * 
     * @param menu Menu实体
     * @return MenuDTO
     */
    public static MenuDTO fromEntity(com.kexio.user.entity.Menu menu) {
        if (menu == null) {
            return null;
        }
        
        MenuDTO dto = new MenuDTO();
        dto.id = menu.getId();
        dto.tenantId = menu.getTenantId();
        dto.parentId = menu.getParentId();
        dto.name = menu.getName();
        dto.title = menu.getTitle();
        dto.path = menu.getPath();
        dto.component = menu.getComponent();
        dto.icon = menu.getIcon();
        dto.menuType = menu.getMenuType();
        dto.permission = menu.getPermission();
        dto.orderNo = menu.getOrderNo();
        dto.isFrame = menu.getIsFrame();
        dto.isCache = menu.getIsCache();
        dto.visible = menu.getVisible();
        dto.status = menu.getStatus();
        dto.metadata = menu.getMetadata();
        dto.createTime = menu.getCreateTime();
        dto.updateTime = menu.getUpdateTime();
        dto.createBy = menu.getCreateBy();
        dto.updateBy = menu.getUpdateBy();
        
        // 注意：可解析metadata JSON为Map格式
        
        return dto;
    }
    
    /**
     * 转换为Menu实体（用于创建和更新）
     * 
     * @return Menu实体
     */
    public com.kexio.user.entity.Menu toEntity() {
        com.kexio.user.entity.Menu menu = new com.kexio.user.entity.Menu();
        
        menu.setId(this.id);
        menu.setTenantId(this.tenantId);
        menu.setParentId(this.parentId);
        menu.setName(this.name);
        menu.setTitle(this.title);
        menu.setPath(this.path);
        menu.setComponent(this.component);
        menu.setIcon(this.icon);
        menu.setMenuType(this.menuType);
        menu.setPermission(this.permission);
        menu.setOrderNo(this.orderNo);
        menu.setIsFrame(this.isFrame);
        menu.setIsCache(this.isCache);
        menu.setVisible(this.visible);
        menu.setStatus(this.status);
        menu.setMetadata(this.metadata);
        menu.setCreateBy(this.createBy);
        menu.setCreateTime(this.createTime);
        menu.setUpdateBy(this.updateBy);
        menu.setUpdateTime(this.updateTime);
        
        return menu;
    }
    
    // ==================== 验证方法 ====================
    
    /**
     * 验证DTO数据的有效性
     * 
     * @throws IllegalArgumentException 如果数据无效
     */
    public void validate() {
        // 基础字段验证
        if (this.name == null || this.name.trim().isEmpty()) {
            throw new IllegalArgumentException("菜单名称不能为空");
        }
        
        if (this.title == null || this.title.trim().isEmpty()) {
            throw new IllegalArgumentException("菜单标题不能为空");
        }
        
        if (this.menuType == null || this.menuType.trim().isEmpty()) {
            throw new IllegalArgumentException("菜单类型不能为空");
        }
        
        if (this.visible == null) {
            throw new IllegalArgumentException("是否可见不能为空");
        }
        
        if (this.status == null) {
            throw new IllegalArgumentException("状态不能为空");
        }
        
        // 清理字符串字段
        this.name = this.name.trim();
        this.title = this.title.trim();
        this.menuType = this.menuType.trim().toUpperCase();
        
        if (this.path != null) {
            this.path = this.path.trim();
            if (this.path.isEmpty()) {
                this.path = null;
            }
        }
        
        if (this.component != null) {
            this.component = this.component.trim();
            if (this.component.isEmpty()) {
                this.component = null;
            }
        }
        
        if (this.icon != null) {
            this.icon = this.icon.trim();
            if (this.icon.isEmpty()) {
                this.icon = null;
            }
        }
        
        if (this.permission != null) {
            this.permission = this.permission.trim();
            if (this.permission.isEmpty()) {
                this.permission = null;
            }
        }
        
        if (this.metadata != null) {
            this.metadata = this.metadata.trim();
            if (this.metadata.isEmpty()) {
                this.metadata = null;
            }
        }
    }
    
    /**
     * 检查是否有任何更新字段（用于更新操作）
     * 
     * @return true-有更新字段，false-无更新字段
     */
    public boolean hasAnyUpdateFields() {
        return this.title != null 
            || this.path != null
            || this.component != null
            || this.icon != null
            || this.menuType != null
            || this.permission != null
            || this.orderNo != null
            || this.isFrame != null
            || this.isCache != null
            || this.visible != null
            || this.status != null
            || this.metadata != null
            || this.parentId != null;
    }
    
    /**
     * 清空ID字段（用于创建操作）
     */
    public void clearIdsForCreate() {
        this.id = null;
        this.createTime = null;
        this.updateTime = null;
    }
    
    // ==================== 便捷方法 ====================
    
    /**
     * 检查是否为启用状态
     * 
     * @return true-启用，false-禁用或未设置
     */
    public boolean isEnabled() {
        return Integer.valueOf(1).equals(this.status);
    }
    
    /**
     * 设置为启用状态
     */
    public void setEnabled() {
        this.status = 1;
    }
    
    /**
     * 设置为禁用状态
     */
    public void setDisabled() {
        this.status = 0;
    }
    
    /**
     * 检查是否为可见状态
     * 
     * @return true-可见，false-隐藏或未设置
     */
    public boolean isVisible() {
        return Boolean.TRUE.equals(this.visible);
    }
    
    /**
     * 设置为可见
     */
    public void setVisibleTrue() {
        this.visible = true;
    }
    
    /**
     * 设置为隐藏
     */
    public void setVisibleFalse() {
        this.visible = false;
    }
    
    /**
     * 检查是否为根菜单（没有父菜单）
     * 
     * @return true-根菜单，false-子菜单
     */
    public boolean isRootMenu() {
        return this.parentId == null;
    }
    
    /**
     * 检查菜单类型是否为目录
     * 
     * @return true-目录，false-其他类型
     */
    public boolean isDirectory() {
        return "M".equals(this.menuType);
    }
    
    /**
     * 检查菜单类型是否为菜单
     * 
     * @return true-菜单，false-其他类型
     */
    public boolean isMenu() {
        return "C".equals(this.menuType);
    }
    
    /**
     * 检查菜单类型是否为按钮
     * 
     * @return true-按钮，false-其他类型
     */
    public boolean isButton() {
        return "F".equals(this.menuType);
    }
    
    /**
     * 检查是否为外链
     * 
     * @return true-外链，false-不是外链或未设置
     */
    public boolean isExternalLink() {
        return Boolean.TRUE.equals(this.isFrame);
    }
    
    /**
     * 检查是否需要缓存
     * 
     * @return true-缓存，false-不缓存或未设置
     */
    public boolean isCached() {
        return Boolean.TRUE.equals(this.isCache);
    }
    
    @Override
    public String toString() {
        return "MenuDTO{" +
                "id=" + id +
                ", tenantId='" + tenantId + '\'' +
                ", parentId=" + parentId +
                ", name='" + name + '\'' +
                ", title='" + title + '\'' +
                ", menuType='" + menuType + '\'' +
                ", visible=" + visible +
                ", status=" + status +
                ", orderNo=" + orderNo +
                '}';
    }
}
